/*
 * RuntimeStatistics.cuh
 *
 *  Created on: Aug 30, 2013
 *      Author: jaime
 */

#ifndef RUNTIMESTATISTICS_CUH_
#define RUNTIMESTATISTICS_CUH_

#include <stdio.h>
#include "../SATSolver/Configs.cuh"
#include "StatisticsCalculator.cuh"
#include "../ErrorHandler/CudaMemoryErrorHandler.cuh"

class RuntimeStatistics {
public:
	RuntimeStatistics(int number_of_blocks, int number_of_threads);
	__device__ void add_completed_jobs(int completed_jobs);
	__device__ void signal_job_start();
	__device__ void signal_job_stop();
	__device__ void signal_preprocess_start();
	__device__ void signal_preprocess_stop();
	__device__ void signal_conflict_analysis_start(int decision_level);
	__device__ void signal_conflict_analysis_stop(int decision_level);
	__device__ void signal_decision_start();
	__device__ void signal_decision_stop();
	__device__ void signal_backtrack_start(int number_of_decisions);
	__device__ void signal_backtrack_stop(int number_of_decisions);
	__device__ void signal_reset_structures_start();
	__device__ void signal_reset_structures_stop();

	/*
	starting structures
	next jobs
	adding jobs to assumptions
	processing results
	*/
	__device__ void signal_create_structures_start();
	__device__ void signal_create_structures_stop();
	__device__ void signal_next_job_start();
	__device__ void signal_next_job_stop();
	__device__ void signal_add_jobs_to_assumptions_start();
	__device__ void signal_add_jobs_to_assumptions_stop();
	__device__ void signal_process_results_start();
	__device__ void signal_process_results_stop();
	__device__ void signal_pre_proc_handle_assumptions_start();
	__device__ void signal_pre_proc_handle_assumptions_stop();
	__device__ void signal_pre_proc_add_to_graph_start();
	__device__ void signal_pre_proc_add_to_graph_stop();
	__device__ void signal_pre_proc_handling_variables_start();
	__device__ void signal_pre_proc_handling_variables_stop();


	__host__ __device__ long long int* get_total_solving_time();
	__host__ __device__ int* get_number_of_jobs_run();
	__host__ __device__ int get_all_threads_total_completed_jobs();
	__host__ __device__ void print_average();
	__host__  void print_function_time_statistics();


	__device__ long long int get_total_time_solving();
	__device__ long long int get_total_deciding_time();
	__device__ long long int get_total_backtracking_time();
	__device__ long long int get_total_conflict_analyzing_time();

	__device__ int get_sum_of_decision_before_backtracking();
	__device__ int get_sum_of_decision_after_backtracking();
	__device__ long long int get_total_backtracked_levels();

	__device__ void signal_start(long long int * total_time, int * occurrences);
	__device__ void signal_start(long long int * total_time,
			int * occurrences, long long int time);
	__device__ void signal_stop(long long int * total_time);
	__device__ void signal_stop(long long int * total_time, long long int time);

private:
	int number_of_blocks;
	int number_of_threads;

	// Time statistics
	long long int* total_solving_time_dev;
	int* number_of_jobs_run_dev;

	// Partial time
	long long int* total_time_analyzing_conflict_dev;
	int* number_conflict_analysis_made_dev;

	long long int* total_time_deciding_dev;
	int* number_decisions_made_dev;

	long long int* total_time_backtracking_dev;
	int* number_backtracks_made_dev;

	long long int* total_time_on_gpu_preprocessing_dev;
	int* number_of_preprocesses_made_dev;

	long long int* total_time_resetting_structures_dev;
	int* number_of_resets_done;


	long long int* total_time_creating_structures_dev;
	int* number_of_create_structures_done;

	long long int* total_time_on_next_job_dev;
	int* number_of_next_job_done;

	long long int* total_time_on_add_jobs_to_assumptions_dev;
	int* number_of_add_jobs_to_assumptions_done;

	long long int* total_time_processing_results_dev;
	int* number_of_process_results_done;



	// Decisions
	int* sum_of_decision_before_backtracking_dev;
	int* sum_of_decision_after_backtracking_dev;
	long long int* total_backtracked_levels_dev;
	int* backtracked_levels_instances_count_dev;
	int* last_backtracked_start_level_dev;

	// Statistics from checking correction
	int* all_threads_total_completed_jobs_dev;

	// Statistics for pre-processing
	long long int* total_time_on_gpu_preprocessing_handling_assumption_dev;
	int* number_of_preprocesses_handling_assumption_made_dev;

	long long int* total_time_on_gpu_preprocessing_adding_to_graph_dev;
	int* number_of_preprocesses_adding_to_graph_made_dev;

	long long int* total_time_on_gpu_preprocessing_handling_variables_dev;
	int* number_of_preprocesses_handling_variables_made_dev;

	__device__ int get_index();

	__host__ void clear_stats(int number_of_blocks, int number_of_threads);
	__host__ void alloc_stats(int number_of_blocks, int number_of_threads);

	template<class T>
	__host__ T* copy_to_host(bool block_thread_vector, T* element_dev);

	__host__ void print_stat_average(long long int* block_thread_stats_dev, int* count_dev, bool use_offset = true);
	__host__ void print_stat_total(long long int* block_thread_stats_dev, int* count_dev);

	template<class T>
	__host__ void print_stat_sum(T* block_thread_stats_dev);
};

template<class T>
__host__ void clear_stat(T* & element, bool block_thread_vector, int number_of_blocks, int number_of_threads);
template<class T>
__host__ void alloc_stat(T* & element, bool block_thread_vector, int number_of_blocks, int number_of_threads);


#endif /* RUNTIMESTATISTICS_CUH_ */
